home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 2007 January, February, March & April
/
Chip-Cover-CD-2007-02.iso
/
Pakiet multimedia
/
Muzyka
/
Edytory sampli (probek dzwieku)
/
ZynAddSubFX_2.2.0
/
Setup_ZynAddSubFX-2.2.0.exe
/
source code
/
Misc
/
Master.C
< prev
next >
Wrap
C/C++ Source or Header
|
2005-03-14
|
19KB
|
739 lines
/*
ZynAddSubFX - a software synthesizer
Master.C - It sends Midi Messages to Parts, receives samples from parts,
process them with system/insertion effects and mix them
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2) for more details.
You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "Master.h"
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
Master::Master(){
swaplr=0;
pthread_mutex_init(&mutex,NULL);
fft=new FFTwrapper(OSCIL_SIZE);
tmpmixl=new REALTYPE[SOUND_BUFFER_SIZE];
tmpmixr=new REALTYPE[SOUND_BUFFER_SIZE];
audiooutl=new REALTYPE[SOUND_BUFFER_SIZE];
audiooutr=new REALTYPE[SOUND_BUFFER_SIZE];
ksoundbuffersample=-1;//this is only time when this is -1; this means that the GetAudioOutSamples was never called
ksoundbuffersamplelow=0.0;
oldsamplel=0.0;oldsampler=0.0;
shutup=0;
for (int npart=0;npart<NUM_MIDI_PARTS;npart++) {
vuoutpeakpart[npart]=1e-9;
fakepeakpart[npart]=0;
};
for (int i=0;i<SOUND_BUFFER_SIZE;i++) {
audiooutl[i]=0.0;
audiooutr[i]=0.0;
};
for (int npart=0;npart<NUM_MIDI_PARTS;npart++)
part[npart]=new Part(µtonal,fft,&mutex);
//Insertion Effects init
for (int nefx=0;nefx<NUM_INS_EFX;nefx++)
insefx[nefx]=new EffectMgr(1,&mutex);
//System Effects init
for (int nefx=0;nefx<NUM_SYS_EFX;nefx++) {
sysefx[nefx]=new EffectMgr(0,&mutex);
};
defaults();
};
void Master::defaults(){
volume=1.0;
setPvolume(80);
setPkeyshift(64);
for (int npart=0;npart<NUM_MIDI_PARTS;npart++){
part[npart]->defaults();
part[npart]->Prcvchn=npart%NUM_MIDI_CHANNELS;
};
partonoff(0,1);//enable the first part
for (int nefx=0;nefx<NUM_INS_EFX;nefx++) {
insefx[nefx]->defaults();
Pinsparts[nefx]=-1;
};
//System Effects init
for (int nefx=0;nefx<NUM_SYS_EFX;nefx++) {
sysefx[nefx]->defaults();
for (int npart=0;npart<NUM_MIDI_PARTS;npart++){
if (nefx==0) setPsysefxvol(npart,nefx,64);
else setPsysefxvol(npart,nefx,0);
};
for (int nefxto=0;nefxto<NUM_SYS_EFX;nefxto++)
setPsysefxsend(nefx,nefxto,0);
};
sysefx[0]->changeeffect(1);
microtonal.defaults();
ShutUp();
};
/*
* Note On Messages (velocity=0 for NoteOff)
*/
void Master::NoteOn(unsigned char chan,unsigned char note,unsigned char velocity){
dump.dumpnote(chan,note,velocity);
noteon(chan,note,velocity);
};
/*
* Internal Note On (velocity=0 for NoteOff)
*/
void Master::noteon(unsigned char chan,unsigned char note,unsigned char velocity){
int npart;
if (velocity!=0){
for (npart=0;npart<NUM_MIDI_PARTS;npart++){
if (chan==part[npart]->Prcvchn){
fakepeakpart[npart]=velocity*2;
if (part[npart]->Penabled!=0) part[npart]->NoteOn(note,velocity,keyshift);
};
};
}else{
this->NoteOff(chan,note);
};
HDDRecorder.triggernow();
};
/*
* Note Off Messages
*/
void Master::NoteOff(unsigned char chan,unsigned char note){
dump.dumpnote(chan,note,0);
noteoff(chan,note);
};
/*
* Internal Note Off
*/
void Master::noteoff(unsigned char chan,unsigned char note){
int npart;
for (npart=0;npart<NUM_MIDI_PARTS;npart++){
if ((chan==part[npart]->Prcvchn) && (part[npart]->Penabled!=0))
part[npart]->NoteOff(note);
};
};
/*
* Controllers
*/
void Master::SetController(unsigned char chan,unsigned int type,int par){
dump.dumpcontroller(chan,type,par);
setcontroller(chan,type,par);
};
/*
* Internal Controllers
*/
void Master::setcontroller(unsigned char chan,unsigned int type,int par){
if ((type==C_dataentryhi)||(type==C_dataentrylo)||
(type==C_nrpnhi)||(type==C_nrpnlo)){//Process RPN and NRPN by the Master (ignore the chan)
ctl.setparameternumber(type,par);
int parhi=-1,parlo=-1,valhi=-1,vallo=-1;
if (ctl.getnrpn(&parhi,&parlo,&valhi,&vallo)==0){//this is NRPN
//fprintf(stderr,"rcv. NRPN: %d %d %d %d\n",parhi,parlo,valhi,vallo);
switch (parhi){
case 0x04://System Effects
if (parlo<NUM_SYS_EFX) {
sysefx[parlo]->seteffectpar_nolock(valhi,vallo);
};
break;
case 0x08://Insertion Effects
if (parlo<NUM_INS_EFX) {
insefx[parlo]->seteffectpar_nolock(valhi,vallo);
};
break;
};
};
} else {//other controllers
for (int npart=0;npart<NUM_MIDI_PARTS;npart++){//Send the controller to all part assigned to the channel
if ((chan==part[npart]->Prcvchn) && (part[npart]->Penabled!=0))
part[npart]->SetController(type,par);
};
};
};
/*
* Enable/Disable a part
*/
void Master::partonoff(int npart,int what){
if (npart>=NUM_MIDI_PARTS) return;
if (what==0){//disable part
fakepeakpart[npart]=0;
part[npart]->Penabled=0;
part[npart]->cleanup();
for (int nefx=0;nefx<NUM_INS_EFX;nefx++){
if (Pinsparts[nefx]==npart) {
insefx[nefx]->cleanup();
};
};
} else {//enabled
part[npart]->Penabled=1;
fakepeakpart[npart]=0;
};
};
/*
* Master audio out (the final sound)
*/
void Master::AudioOut(REALTYPE *outl,REALTYPE *outr){
int i,npart,nefx;
/* //test!!!!!!!!!!!!! se poate bloca aici (mutex)
if (seq.play){
int type,par1,par2,again,midichan;
int ntrack=1;
// do{
again=seq.getevent(ntrack,&midichan,&type,&par1,&par2);
if (type>0) {
// printf("aaa\n");
if (type==1){//note_on or note_off
if (par2!=0) NoteOn(midichan,par1,par2);
else NoteOff(midichan,par1);
};
};
// } while (again);
};
*/
// printf("zzzz\n");
//Swaps the Left channel with Right Channel (if it is asked for)
if (swaplr!=0){
REALTYPE *tmp=outl;
outl=outr;
outr=tmp;
};
//clean up the output samples
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
outl[i]=0.0;
outr[i]=0.0;
};
//Compute part samples and store them part[npart]->partoutl,partoutr
for (npart=0;npart<NUM_MIDI_PARTS;npart++)
if (part[npart]->Penabled!=0) part[npart]->ComputePartSmps();
//Insertion effects
for (nefx=0;nefx<NUM_INS_EFX;nefx++){
if (Pinsparts[nefx]>=0) {
int efxpart=Pinsparts[nefx];
if (part[efxpart]->Penabled!=0)
insefx[nefx]->out(part[efxpart]->partoutl,part[efxpart]->partoutr);
};
};
//Apply the part volumes and pannings (after insertion effects)
for (npart=0;npart<NUM_MIDI_PARTS;npart++){
if (part[npart]->Penabled==0) continue;
REALTYPE newvol_l=part[npart]->volume;
REALTYPE newvol_r=part[npart]->volume;
REALTYPE oldvol_l=part[npart]->oldvolumel;
REALTYPE oldvol_r=part[npart]->oldvolumer;
REALTYPE pan=part[npart]->panning;
if (pan<0.5) newvol_l*=pan*2.0;
else newvol_r*=(1.0-pan)*2.0;
if (ABOVE_AMPLITUDE_THRESHOLD(oldvol_l,newvol_l)||
ABOVE_AMPLITUDE_THRESHOLD(oldvol_r,newvol_r)){//the volume or the panning has changed and needs interpolation
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
REALTYPE vol_l=INTERPOLATE_AMPLITUDE(oldvol_l,newvol_l,i,SOUND_BUFFER_SIZE);
REALTYPE vol_r=INTERPOLATE_AMPLITUDE(oldvol_r,newvol_r,i,SOUND_BUFFER_SIZE);
part[npart]->partoutl[i]*=vol_l;
part[npart]->partoutr[i]*=vol_r;
};
part[npart]->oldvolumel=newvol_l;
part[npart]->oldvolumer=newvol_r;
} else {
for (i=0;i<SOUND_BUFFER_SIZE;i++) {//the volume did not changed
part[npart]->partoutl[i]*=newvol_l;
part[npart]->partoutr[i]*=newvol_r;
};
};
};
//System effects
for (nefx=0;nefx<NUM_SYS_EFX;nefx++){
if (sysefx[nefx]->geteffect()==0) continue;//the effect is disabled
//Clean up the samples used by the system effects
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
tmpmixl[i]=0.0;
tmpmixr[i]=0.0;
};
//Mix the channels according to the part settings about System Effect
for (npart=0;npart<NUM_MIDI_PARTS;npart++){
//skip if the part has no output to effect
if (Psysefxvol[nefx][npart]==0) continue;
//skip if the part is disabled
if (part[npart]->Penabled==0) continue;
//the output volume of each part to system effect
REALTYPE vol=sysefxvol[nefx][npart];
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
tmpmixl[i]+=part[npart]->partoutl[i]*vol;
tmpmixr[i]+=part[npart]->partoutr[i]*vol;
};
};
// system effect send to next ones
for (int nefxfrom=0;nefxfrom<nefx;nefxfrom++){
if (Psysefxsend[nefxfrom][nefx]!=0){
REALTYPE v=sysefxsend[nefxfrom][nefx];
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
tmpmixl[i]+=sysefx[nefxfrom]->efxoutl[i]*v;
tmpmixr[i]+=sysefx[nefxfrom]->efxoutr[i]*v;
};
};
};
sysefx[nefx]->out(tmpmixl,tmpmixr);
//Add the System Effect to sound output
REALTYPE outvol=sysefx[nefx]->sysefxgetvolume();
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
outl[i]+=tmpmixl[i]*outvol;
outr[i]+=tmpmixr[i]*outvol;
};
};
//Mix all parts
for (npart=0;npart<NUM_MIDI_PARTS;npart++){
for (i=0;i<SOUND_BUFFER_SIZE;i++) {//the volume did not changed
outl[i]+=part[npart]->partoutl[i];
outr[i]+=part[npart]->partoutr[i];
};
};
//Insertion effects for Master Out
for (nefx=0;nefx<NUM_INS_EFX;nefx++){
if (Pinsparts[nefx] == -2)
insefx[nefx]->out(outl,outr);
};
//Master Volume
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
outl[i]*=volume;
outr[i]*=volume;
};
//Peak computation (for vumeters)
vuoutpeakl=1e-12;vuoutpeakr=1e-12;
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
if (fabs(outl[i])>vuoutpeakl) vuoutpeakl=fabs(outl[i]);
if (fabs(outr[i])>vuoutpeakr) vuoutpeakr=fabs(outr[i]);
};
if ((vuoutpeakl>1.0)||(vuoutpeakr>1.0)) vuclipped=1;
if (vumaxoutpeakl<vuoutpeakl) vumaxoutpeakl=vuoutpeakl;
if (vumaxoutpeakr<vuoutpeakr) vumaxoutpeakr=vuoutpeakr;
//RMS Peak computation (for vumeters)
vurmspeakl=1e-12;vurmspeakr=1e-12;
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
vurmspeakl+=outl[i]*outl[i];
vurmspeakr+=outr[i]*outr[i];
};
vurmspeakl=sqrt(vurmspeakl/SOUND_BUFFER_SIZE);
vurmspeakr=sqrt(vurmspeakr/SOUND_BUFFER_SIZE);
//Part Peak computation (for Part vumeters or fake part vumeters)
for (npart=0;npart<NUM_MIDI_PARTS;npart++){
vuoutpeakpart[npart]=1.0e-12;
if (part[npart]->Penabled!=0) {
REALTYPE *outl=part[npart]->partoutl,
*outr=part[npart]->partoutr;
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
REALTYPE tmp=fabs(outl[i]+outr[i]);
if (tmp>vuoutpeakpart[npart]) vuoutpeakpart[npart]=tmp;
};
vuoutpeakpart[npart]*=volume;
} else {
if (fakepeakpart[npart]>1) fakepeakpart[npart]--;
};
};
//Shutup if it is asked (with fade-out)
if (shutup!=0){
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
REALTYPE tmp=(SOUND_BUFFER_SIZE-i)/(REALTYPE) SOUND_BUFFER_SIZE;
outl[i]*=tmp;
outr[i]*=tmp;
};
ShutUp();
};
//update the LFO's time
LFOParams::time++;
if (HDDRecorder.recording()) HDDRecorder.recordbuffer(outl,outr);
dump.inctick();
};
void Master::GetAudioOutSamples(int nsamples,int samplerate,REALTYPE *outl,REALTYPE *outr){
if (ksoundbuffersample==-1){//first time
AudioOut(&audiooutl[0],&audiooutr[0]);
ksoundbuffersample=0;
};
if (samplerate==SAMPLE_RATE){//no resample
int ksample=0;
while (ksample<nsamples){
outl[ksample]=audiooutl[ksoundbuffersample];
outr[ksample]=audiooutr[ksoundbuffersample];
ksample++;
ksoundbuffersample++;
if (ksoundbuffersample>=SOUND_BUFFER_SIZE){
AudioOut(&audiooutl[0],&audiooutr[0]);
ksoundbuffersample=0;
};
};
} else {//Resample
int ksample=0;
REALTYPE srinc=SAMPLE_RATE/(REALTYPE)samplerate;
while (ksample<nsamples){
if (ksoundbuffersample!=0){
outl[ksample]=audiooutl[ksoundbuffersample]*ksoundbuffersamplelow
+audiooutl[ksoundbuffersample-1]*(1.0-ksoundbuffersamplelow);
outr[ksample]=audiooutr[ksoundbuffersample]*ksoundbuffersamplelow
+audiooutr[ksoundbuffersample-1]*(1.0-ksoundbuffersamplelow);
} else {
outl[ksample]=audiooutl[ksoundbuffersample]*ksoundbuffersamplelow
+oldsamplel*(1.0-ksoundbuffersamplelow);
outr[ksample]=audiooutr[ksoundbuffersample]*ksoundbuffersamplelow
+oldsampler*(1.0-ksoundbuffersamplelow);
};
ksample++;
ksoundbuffersamplelow+=srinc;
if (ksoundbuffersamplelow>=1.0){
ksoundbuffersample+=(int) floor(ksoundbuffersamplelow);
ksoundbuffersamplelow=ksoundbuffersamplelow-floor(ksoundbuffersamplelow);
};
if (ksoundbuffersample>=SOUND_BUFFER_SIZE){
oldsamplel=audiooutl[SOUND_BUFFER_SIZE-1];
oldsampler=audiooutr[SOUND_BUFFER_SIZE-1];
AudioOut(&audiooutl[0],&audiooutr[0]);
ksoundbuffersample=0;
};
};
};
};
Master::~Master(){
for (int npart=0;npart<NUM_MIDI_PARTS;npart++) delete (part[npart]);
for (int nefx=0;nefx<NUM_INS_EFX;nefx++) delete (insefx[nefx]);
for (int nefx=0;nefx<NUM_SYS_EFX;nefx++) delete (sysefx[nefx]);
delete [] audiooutl;
delete [] audiooutr;
delete [] tmpmixl;
delete [] tmpmixr;
delete (fft);
pthread_mutex_destroy(&mutex);
};
/*
* Parameter control
*/
void Master::setPvolume(char Pvolume_){
Pvolume=Pvolume_;
volume=dB2rap((Pvolume-96.0)/96.0*40.0);
};
void Master::setPkeyshift(char Pkeyshift_){
Pkeyshift=Pkeyshift_;
keyshift=(int)Pkeyshift-64;
};
void Master::setPsysefxvol(int Ppart,int Pefx,char Pvol){
Psysefxvol[Pefx][Ppart]=Pvol;
sysefxvol[Pefx][Ppart]=pow(0.1,(1.0-Pvol/96.0)*2.0);
};
void Master::setPsysefxsend(int Pefxfrom,int Pefxto,char Pvol){
Psysefxsend[Pefxfrom][Pefxto]=Pvol;
sysefxsend[Pefxfrom][Pefxto]=pow(0.1,(1.0-Pvol/96.0)*2.0);
};
/*
* Panic! (Clean up all parts and effects)
*/
void Master::ShutUp(){
for (int npart=0;npart<NUM_MIDI_PARTS;npart++) {
part[npart]->cleanup();
fakepeakpart[npart]=0;
};
for (int nefx=0;nefx<NUM_INS_EFX;nefx++) insefx[nefx]->cleanup();
for (int nefx=0;nefx<NUM_SYS_EFX;nefx++) sysefx[nefx]->cleanup();
vuresetpeaks();
shutup=0;
};
/*
* Reset peaks and clear the "cliped" flag (for VU-meter)
*/
void Master::vuresetpeaks(){
vuoutpeakl=1e-9;vuoutpeakr=1e-9;vumaxoutpeakl=1e-9;vumaxoutpeakr=1e-9;
vuclipped=0;
};
void Master::applyparameters(){
for (int npart=0;npart<NUM_MIDI_PARTS;npart++){
part[npart]->applyparameters();
};
};
void Master::add2XML(XMLwrapper *xml){
xml->addpar("volume",Pvolume);
xml->addpar("key_shift",Pkeyshift);
xml->addparbool("nrpn_receive",ctl.NRPN.receive);
xml->beginbranch("MICROTONAL");
microtonal.add2XML(xml);
xml->endbranch();
for (int npart=0;npart<NUM_MIDI_PARTS;npart++){
xml->beginbranch("PART",npart);
part[npart]->add2XML(xml);
xml->endbranch();
};
xml->beginbranch("SYSTEM_EFFECTS");
for (int nefx=0;nefx<NUM_SYS_EFX;nefx++){
xml->beginbranch("SYSTEM_EFFECT",nefx);
xml->beginbranch("EFFECT");
sysefx[nefx]->add2XML(xml);
xml->endbranch();
for (int pefx=0;pefx<NUM_MIDI_PARTS;pefx++){
xml->beginbranch("VOLUME",pefx);
xml->addpar("vol",Psysefxvol[nefx][pefx]);
xml->endbranch();
};
for (int tonefx=nefx+1;tonefx<NUM_SYS_EFX;tonefx++){
xml->beginbranch("SENDTO",tonefx);
xml->addpar("send_vol",Psysefxsend[nefx][tonefx]);
xml->endbranch();
};
xml->endbranch();
};
xml->endbranch();
xml->beginbranch("INSERTION_EFFECTS");
for (int nefx=0;nefx<NUM_INS_EFX;nefx++){
xml->beginbranch("INSERTION_EFFECT",nefx);
xml->addpar("part",Pinsparts[nefx]);
xml->beginbranch("EFFECT");
insefx[nefx]->add2XML(xml);
xml->endbranch();
xml->endbranch();
};
xml->endbranch();
};
int Master::getalldata(char **data){
XMLwrapper *xml=new XMLwrapper();
xml->beginbranch("MASTER");
pthread_mutex_lock(&mutex);
add2XML(xml);
pthread_mutex_unlock(&mutex);
xml->endbranch();
*data=xml->getXMLdata();
delete (xml);
return(strlen(*data)+1);
};
void Master::putalldata(char *data,int size){
XMLwrapper *xml=new XMLwrapper();
if (!xml->putXMLdata(data)) {
delete(xml);
return;
};
if (xml->enterbranch("MASTER")==0) return;
pthread_mutex_lock(&mutex);
getfromXML(xml);
pthread_mutex_unlock(&mutex);
xml->exitbranch();
delete(xml);
};
int Master::saveXML(char *filename){
XMLwrapper *xml=new XMLwrapper();
xml->beginbranch("MASTER");
add2XML(xml);
xml->endbranch();
int result=xml->saveXMLfile(filename);
delete (xml);
return(result);
};
int Master::loadXML(char *filename){
XMLwrapper *xml=new XMLwrapper();
if (xml->loadXMLfile(filename)<0) {
delete(xml);
return(-1);
};
if (xml->enterbranch("MASTER")==0) return(-10);
getfromXML(xml);
xml->exitbranch();
delete(xml);
return(0);
};
void Master::getfromXML(XMLwrapper *xml){
setPvolume(xml->getpar127("volume",Pvolume));
setPkeyshift(xml->getpar127("key_shift",Pkeyshift));
ctl.NRPN.receive=xml->getparbool("nrpn_receive",ctl.NRPN.receive);
part[0]->Penabled=0;
for (int npart=0;npart<NUM_MIDI_PARTS;npart++){
if (xml->enterbranch("PART",npart)==0) continue;
part[npart]->getfromXML(xml);
xml->exitbranch();
};
if (xml->enterbranch("MICROTONAL")){
microtonal.getfromXML(xml);
xml->exitbranch();
};
sysefx[0]->changeeffect(0);
if (xml->enterbranch("SYSTEM_EFFECTS")){
for (int nefx=0;nefx<NUM_SYS_EFX;nefx++){
if (xml->enterbranch("SYSTEM_EFFECT",nefx)==0) continue;
if (xml->enterbranch("EFFECT")){
sysefx[nefx]->getfromXML(xml);
xml->exitbranch();
};
for (int partefx=0;partefx<NUM_MIDI_PARTS;partefx++){
if (xml->enterbranch("VOLUME",partefx)==0) continue;
setPsysefxvol(partefx,nefx,xml->getpar127("vol",Psysefxvol[partefx][nefx]));
xml->exitbranch();
};
for (int tonefx=nefx+1;tonefx<NUM_SYS_EFX;tonefx++){
if (xml->enterbranch("SENDTO",tonefx)==0) continue;
setPsysefxsend(nefx,tonefx,xml->getpar127("send_vol",Psysefxsend[nefx][tonefx]));
xml->exitbranch();
};
xml->exitbranch();
};
xml->exitbranch();
};
if (xml->enterbranch("INSERTION_EFFECTS")){
for (int nefx=0;nefx<NUM_INS_EFX;nefx++){
if (xml->enterbranch("INSERTION_EFFECT",nefx)==0) continue;
Pinsparts[nefx]=xml->getpar("part",Pinsparts[nefx],-1,NUM_MIDI_PARTS);
if (xml->enterbranch("EFFECT")){
insefx[nefx]->getfromXML(xml);
xml->exitbranch();
};
xml->exitbranch();
};
xml->exitbranch();
};
};